#include "CapitalMarketAssets.h"
#include "../FIDataCenter.h"
#include "CapitalMarketSettings.h"
#include "../StringResource.h"
#include <core/time/time.h>
#include <core/StyleMgr.h>
#include <uam/ServerTimeMgr.h>
#include <widgets/SImageButton.h>
#include <widgets/table/STable.h>
#include <widgets/table/STableColumnSet.h>
#include <QVBoxLayout>
#include <QLabel>
#include <QColor>
#include <QScrollBar>
#include <QTableView>
#include <QHeaderView>
#include <uam/UserAccountManager.h>
#include "../data/FI_GMKTIndexData.h"

namespace
{
#define ALIGN_LEFT  (Qt::Alignment)(Qt::AlignVCenter | Qt::AlignLeft)
#define ALIGN_RIGHT  (Qt::Alignment)(Qt::AlignVCenter | Qt::AlignRight)

}

class AMVirtualTable : public SVirtualTable
{
public:
    AMVirtualTable(QWidget* p):SVirtualTable(p) {}
protected:
    void resizeEvent(QResizeEvent* event) override {
        // we override resizeEvent to let it do nothing
    }
    bool eventFilter(QObject* watched, QEvent* event) override {
        // we override eventFilter to let it do nothing
        return false;
    }
};

CapitalMarketAssets::CapitalMarketAssets(QString strTitle, QWidget* parent)
	: SDialog(parent)
{
	setTitle(strTitle);
    setEnableSetting(true);

    /*QHBoxLayout* titleLayout = qobject_cast<QHBoxLayout*>(m_title->layout());
	if (titleLayout)
	{
        m_lblUpdateTime = new QLabel("", this);
        m_lblUpdateTime->show();
        titleLayout->insertWidget(3, m_lblUpdateTime);

        QString styleSheet = QString("color:#%1")
            .arg(StyleMgr::instance().color("SupportingWord").rgb(), 0, 16);
        m_lblUpdateTime->setStyleSheet(styleSheet);
        QFont fn = m_title->font();
        fn.setPixelSize(11);
        m_lblUpdateTime->setFont(fn);
    }*/

	QLayout* layout = this->layout();

    m_list = new AMVirtualTable(this);
	m_model = new DefaultTableModel(this);
	m_model->setTable(m_list);
	layout->addWidget(m_list);

	m_list->setHeaderSortable(true);
	m_list->table()->setModel(m_model);
	m_list->table()->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
	m_list->table()->horizontalHeader()->setSectionsMovable(true);
	m_list->table()->horizontalHeader()->show();
	m_list->table()->setContextMenuPolicy(Qt::CustomContextMenu);

    // use the native scroll bar of QTableView
    m_list->table()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);

    connect(&FIDataCenter::instance(), &FIDataCenter::recvGMktIndex, this, &CapitalMarketAssets::onGMktIndexDataArrived);

    connect(&CapitalMarketSettings::instance(CapitalMarketSettings::Assets), &CapitalMarketSettings::orderChanged, this, &CapitalMarketAssets::onOrderChanged );

    initTable();
}

void CapitalMarketAssets::onOrderChanged()
{
    initModel();
}

static int mapCapitalMarketItemID_2_GMktIndexID(const int item_id) {
    const int IndexID_start = CapitalMarketSettings::getBaseId(CapitalMarketSettings::Index);
    const int IRSID_start = CapitalMarketSettings::getBaseId(CapitalMarketSettings::IRS);
    if (item_id >= IndexID_start) {
        return FIGMktIndexPriceData::SSEC + item_id - IndexID_start;
    } else if (item_id >= IRSID_start) {
        return FIGMktIndexPriceData::IRS_FR1Y + item_id - IRSID_start;
    }
    return -1;
}

void CapitalMarketAssets::initModel()
{
    QFont f = font();
    f.setPixelSize(13);
    f.setBold(true);

    m_model->setRowCount(0);
    const std::vector<int>& current_order = CapitalMarketSettings::instance(CapitalMarketSettings::Assets).getOrder();
    m_model->setRowCount(current_order.size());
    int row = 0;
    for(const auto& id : current_order) {
        QStandardItem* item = new QStandardItem();
        item->setData(f, Qt::FontRole);
        item->setData(id, DataIdRole);
        item->setData(CapitalMarketSettings::getName(id), Qt::DisplayRole);
        item->setData(StyleMgr::instance().color("TextNormal"), Qt::ForegroundRole);
        item->setData((int)(ALIGN_LEFT), Qt::TextAlignmentRole);

        m_model->setItem(row++, 0, item);
    }
    std::vector<int> current_indexes(current_order.size(), -1);
    std::transform(current_order.begin(), current_order.end(), current_indexes.begin(), mapCapitalMarketItemID_2_GMktIndexID);
    FIDataCenter::instance().reqGMktIndex(current_indexes);
}

void CapitalMarketAssets::initTable()
{
	m_tableSet = new STableColumnSet(m_list, "", this);

	BEGIN_COLUMN;
    ADD_COLUMN(COL_NAME, m_tableSet, NewStringTable::strAssetMarketListHead(COL_NAME), 0, 60, 20, 0.33, false, ALIGN_LEFT, kAuto, "");
    ADD_COLUMN(COL_PRICE, m_tableSet, NewStringTable::strAssetMarketListHead(COL_PRICE), 0, 60, 20, 0.33, false, ALIGN_RIGHT, kAuto, "");
    ADD_COLUMN(COL_CHANGE, m_tableSet, NewStringTable::strAssetMarketListHead(COL_CHANGE), 0, 60, 20, 0.34, false, ALIGN_RIGHT, kAuto, "");
	m_tableSet->apply();

    initModel();
    //updateTable();
}

void CapitalMarketAssets::updateTable(bool reset)
{
    //onGMktIndexDataArrived(true);
}

static QString formatPrice(FIGMktIndexPriceData::GMktIndexID indexId, const QString& price) {
    int precision = 2;
    switch(indexId) {
        case FIGMktIndexPriceData::IRS_FR1Y:
        case FIGMktIndexPriceData::IRS_FR5Y:
        case FIGMktIndexPriceData::IRS_SHIBOR1Y:
        case FIGMktIndexPriceData::IRS_SHIBOR5Y:
        case FIGMktIndexPriceData::USDX:
        case FIGMktIndexPriceData::US10YR: {
            precision = 4;
        } break;
        case FIGMktIndexPriceData::SSEC:
        case FIGMktIndexPriceData::CSI300:
        case FIGMktIndexPriceData::SZI:
        case FIGMktIndexPriceData::XIN9:
        case FIGMktIndexPriceData::HSI:
        case FIGMktIndexPriceData::VIX:
        case FIGMktIndexPriceData::GEM: {
            precision = 2;
        } break;
        case FIGMktIndexPriceData::WTICRUDE:
        case FIGMktIndexPriceData::BRENTCRUDE: {
            precision = 3;
        } break;
        default:
            break;
    }

    bool ok=false;
    const double value = price.toDouble(&ok);
    return ok ? QString::number(value,'f', precision) : "--";
}

static QString formatChange(FIGMktIndexPriceData::GMktIndexID indexId, const QString& updownValue, const QString& updownPoint) {
    const QString* inputValue=&updownValue;
    QString unit = "%";
    int precision = 2;
    switch(indexId) {
    case FIGMktIndexPriceData::IRS_FR1Y:
    case FIGMktIndexPriceData::IRS_FR5Y:
    case FIGMktIndexPriceData::IRS_SHIBOR1Y:
    case FIGMktIndexPriceData::IRS_SHIBOR5Y:
    case FIGMktIndexPriceData::US10YR: {
        inputValue = &updownPoint;
        unit = "bp";
    } break;
    default: {
    } break;
    }

    bool ok=false;
    const double value = inputValue->toDouble(&ok);
    if (ok) {
        return QString("%1%2%3").arg( ((value > 0)?"+":""), QString::number(value,'f', precision), unit);
    }
    return "--";
}
void CapitalMarketAssets::onGMktIndexDataArrived(int indexID, bool dataChange)
{
    std::vector<FIGMktIndexPriceData::GMktIndexID> updated_indexIDs;
    if (indexID == FIGMktIndexPriceData::MaxCount) {
        // update all
        updated_indexIDs.reserve(indexID);
        for (int i = 0; i < indexID; ++i) {
            updated_indexIDs.push_back(static_cast<FIGMktIndexPriceData::GMktIndexID>(i));
        }
    } else {
        // update one
        updated_indexIDs.push_back(static_cast<FIGMktIndexPriceData::GMktIndexID>(indexID));
    }

    QFont f = font();
    f.setPixelSize(13);
    f.setBold(true);

    QString price, updownValue, updownPoint;
    time_t time;

    auto find_row_by_GMktIndexID = [this](const int GMktIndexID){
        int row = 0;
        for(; row < this->m_model->rowCount(); ++row) {
            QStandardItem* item = this->m_model->item(row);
            if (item) {
                bool ok=false;
                const int item_id = item->data(DataIdRole).toInt(&ok);
                if (ok && (mapCapitalMarketItemID_2_GMktIndexID(item_id) == GMktIndexID))
                    break;
            }
        }
        return row;
    };

    for (const auto i : updated_indexIDs) {
        if (FIDataCenter::instance().m_dataGMktIndex.getData(i, price, updownValue, updownPoint, time)) {
            //convert FIGMktIndexPriceData::GMktIndexID to CapitalMarketSettings::CapitalMarketItemID
            const int row = find_row_by_GMktIndexID(i);

            if (row != m_model->rowCount()) {
                for (int col = 1; col < COL_COUNT; ++col) {
                    QStandardItem* item = m_model->item(row, col);
                    if (item == nullptr) {
                        item = new QStandardItem();
                        item->setData(f, Qt::FontRole);
                        item->setData((int)(ALIGN_RIGHT), Qt::TextAlignmentRole);
                        item->setData(StyleMgr::instance().color("Highlight"), Qt::ForegroundRole);
                    }

                    switch (col)
                    {
                    case COL_PRICE:
                        item->setData(formatPrice(i, price), Qt::DisplayRole);
                        break;
                    case COL_CHANGE: {
                        const QString& displayTxt = formatChange(i, updownValue, updownPoint);
                        item->setData(displayTxt, Qt::DisplayRole);
                        bool is_reduce = displayTxt.startsWith('-');
                        if ( displayTxt.endsWith("bp") )
                            is_reduce = !is_reduce;

                        const QColor clrBP = StyleMgr::instance().color(is_reduce ? "Down_Reduce_H1" : "Up_Increase_H1");
                        item->setData(clrBP, Qt::ForegroundRole);
                    } break;
                    default:
                        break;
                    }
                    m_model->setItem(row, col, item);
                }

                FlashInfo fi;
                fi.entireRow = true;
                fi.id = QString::number(i);
                m_list->addFlashInfo(fi, true);
            }
        }
    }

}


SDialog* CapitalMarketAssets::clone(QWidget* parent)
{
    CapitalMarketAssets* cloned = new CapitalMarketAssets(m_strTitle, parent);
    SImageButton* a =   this->findChild<SImageButton*>(SDialogTitle::kbtnSettingObjName);
    SImageButton* b = cloned->findChild<SImageButton*>(SDialogTitle::kbtnSettingObjName);
    if (nullptr != a && nullptr != b) {
        connect(b, &SImageButton::clicked, a, &SImageButton::clicked);
    }
    return cloned;
}

